﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Pipra.Gis;
using Pipra.Gis.Projection;
using Pipra.Gis.Transformation;
using Pipra.Math;
using Pipra.Math.Geometry;

namespace CompilationSandbox
{
    class Program
    {

        static void Main(string[] args)
        {

            var ht1 = new Helmert7Transformation(
                new Vector3(0, 0, 4.5),
                new Vector3(0, 0, 0.000002685868),
                1.0 + (0.219/10e6)
            );
            var ht2 = ht1.GetInverse();
            var gct1 = new GeocentricTranslation(new Vector3(1, 2, 3));
            var geocgeog = new GeographicGeocentricTransformation(
                new SpheroidEquatorialInvF(6378137, 298.257223563)
            ).GetInverse() as ITransformation<Point3, LatLon>;
            var merc = new Mercator(
                new LatLon(0, 0),
                new Point2(0, 0),
                new SpheroidEquatorialInvF(6378137, 298.257223563)
            );

            var compiled = new CoordinateOperationCompiled<Point3, Point2>(
                new ITransformation[]
                {
                    ht1,
                    ht2,
                    gct1,
                    geocgeog,
                    merc
                }
            );

            var res1 =
                merc.TransformValue(
                geocgeog.TransformValue(
                gct1.TransformValue(
                ht2.TransformValue(
                ht1.TransformValue(
                new Point3(1, 2, 3)
            )))));
            var res2 = compiled.TransformValue(new Point3(1, 2, 3));

            if (res1 != res2)
            {
                throw new InvalidOperationException();
            }

            Stopwatch watch;
            Point3[] data;
            Point2[] data2;
            int n = 100000;
            double d;

            data = GeneratePoints(n);
            data2 = new Point2[n];
            watch = new Stopwatch();
            watch.Start();
            for (int i = 0; i < data.Length; i++)
            {
                data2[i] = merc.TransformValue(
                    geocgeog.TransformValue(
                    gct1.TransformValue(
                    ht2.TransformValue(
                    ht1.TransformValue(
                    data[i]
                )))));
            }
            watch.Stop();
            d = data2[10].Distance(data2[data2.Length - 1]);
            Console.WriteLine(watch.ElapsedTicks);

            data = GeneratePoints(n);
            data2 = new Point2[n];
            watch = new Stopwatch();
            watch.Start();
            for (int i = 0; i < data.Length; i++)
            {
                data2[i] = compiled.TransformValue(data[i]);
            }
            watch.Stop();
            d = data2[10].Distance(data2[data2.Length - 1]);
            Console.WriteLine(watch.ElapsedTicks);

            Console.ReadKey();

        }

        static Point3[] GeneratePoints(int n)
        {
            var r = new Random(1234);
            var data = new Point3[n];
            for(var i = 0; i < data.Length;i++)
            {
                data[i] = new Point3(
                    r.NextDouble(),
                    r.NextDouble(),
                    r.NextDouble()
                );
            }
            return data;
        }



    }
}
